# -*- Mode: asm-mode -*-
/*
  S.M.A.C.K - An operating system kernel
  Copyright (C) 2010,2011 Mattias Holm and Kristian Rietveld
  For licensing and a full list of authors of the kernel, see the files
  COPYING and AUTHORS.
*/
	# Mode symbols for use by cps instruction
	.equ USR_MODE, 0b10000
	.equ FIQ_MODE, 0b10001
	.equ IRQ_MODE, 0b10010
	.equ SVC_MODE, 0b10011
	.equ MON_MODE, 0b10110
	.equ ABT_MODE, 0b10111
	.equ UND_MODE, 0b11011
	.equ SYS_MODE, 0b11111

# Important note regarding function calls in this file. The code in this file
# will be relocated, and placed at either 0x00000000 or 0xffff0000, thus:
#   All function calls to anything defined outside this file, must be to absolute
#   addresses (i.e. far calls).
	.text
        b _reset			@ 0x00
	b _undef			@ 0x04
	b _swi				@ 0x08
	b _pref_abort			@ 0x0c
	b _data_abort			@ 0x10
	b _panic			@ Reserved, should just hang
	b _isr				@ 0x18
	# FIQ handler here
_fiq:	ldr pc, =panic			@ 0x1c
	nop
	nop
	nop
	nop
	nop
	nop

_reset:	ldr pc, =panic
_undef: push  {r0-r12, lr}
	ldr pc, =panic
	pop  {r0-r12, lr}
	movs pc, lr

# NOTE: Changes to this should be reflected in hw_proc_dup().
_swi:	push  {r1-r12, lr}		@ When nesting, also need r13 and r14
	# Note that r1 contains pointer to argument structure

	# Save SPSR on stack
	mrs r2, spsr
	push {r2}

	ldr r0, [lr, #-4]		@ Get the syscall instruction
	bic r0, r0, #0xff000000		@ Clear opcode bits (extract syscall no)
	ldr lr, =1f
	ldr pc, =syscall		@ Call the C syscall function syscall:
					@ Syscall id is in r0.
					@ Pointer to arg structure in r1.
	# Note that on return, r0 contains the return value

	# Restore SPSR from stack
1:	pop {r2}
	msr spsr, r2
	pop {r1-r12, lr}		@ Restore r1-r12 and LR
	movs pc, lr			@ Restore PC and CPSR

_pref_abort:
        push {r0-r12, lr}
	ldr pc, =mmu_prefetch_abort
        pop {r0-r12, lr}
	subs pc, lr, #4
_data_abort:
	push {r0-r12, lr}
	# Supply fault instruction (approx. lr) as first argument
	mov r0, lr
	ldr pc, =mmu_data_abort
	pop {r0-r12, lr}
	subs pc, lr, #8
_panic:	push  {r0-r12, lr}
	ldr pc, =panic


	# The interrupt handler will store the current context on the stack.
	# The pre-empt routine might replace the context stored on the stack
	# with another context.  The format of the context on the stack
	# follows cpu_ctxt_t (arch/arm/arch-process.h).

	# Allocate space on the stack for the context
_isr:	sub sp, sp, #(20*4)

	# Store first set of general purpose registers
	stm sp, {r0-r12}

	# Store remainder of the process context, such as SP and LR in
	# SYS and SVC mode
	mov r2, lr
	cps #SYS_MODE
	mov r0, r13
	mov r1, r14
	cps #SVC_MODE
	mov r3, r13
	mov r4, r14
	cps #IRQ_MODE
	mrs r5, spsr

	# Calculate offset into context structure to store remainder of the
	# context.
	mov r6, sp
	add r6, r6, #(13*4)
	stm r6, {r0-r5}

	# Save lr value to return to and jump to interrupt handling code
	# written in C
	ldr lr, =1f			@ point to return after function call
	ldr pc, =interrupt
1:

	# Calculate offset into process context where remainder of process
	# context is stored.  And restore t hese values.
	add sp, sp, #(13*4)
	ldm sp, {r0-r5}
	mov lr, r2
	msr spsr, r5
	cps #SYS_MODE
	mov r13, r0
	mov r14, r1
	cps #SVC_MODE
	mov r13, r3
	mov r14, r4
	cps #IRQ_MODE

	# Restore first set of general purpose registers
	sub sp, sp, #(13*4)
	ldm sp, {r0-r12}

	# Free the stack space occupied by the process context
	add sp, sp, #(20*4)

	# We may have switched context, clear exclusive state
	clrex

	# Restore pc from link register, restore cpsr from spsr
        subs pc, lr, #4
	.end
